﻿using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using LuckyShell.Parsers;
using LuckyShell.ShellOrders;
using sly.parser;
using sly.parser.generator;

namespace LuckyShell;

public class Interpreter
{
    #region Code

    private BlockOrder Block { get; set; } = new([]);

    private VariateManager Manager;

    [NotNull] private Parser<ShellTokenGeneric, ShellTree>? BuildResult { get; set; }

    #endregion

    #region RunTime

    public string? Time { get; private set; }
    private double DoubleTime { get; set; }

    public List<string> Error { get; } = new();

    #endregion

    public Interpreter()
    {
        Manager = new VariateManager();
        Init();
    }

    private void Init()
    {
        var sw = new Stopwatch();
        sw.Start();
        var parser = new ParserBuilder<ShellTokenGeneric, ShellTree>();
        var shellParser = new ShellParser();
        var parserBuilder = parser.BuildParser(shellParser,
            ParserType.EBNF_LL_RECURSIVE_DESCENT, "root");
        BuildResult = parserBuilder.Result;
        sw.Stop();
        var ts = sw.Elapsed;
        Console.WriteLine($"Initialization Successful, Time is: {ts.TotalMilliseconds}ms");
        DoubleTime += ts.TotalMilliseconds;
    }

    public void RunTest(string code)
    {
        Time = "";
        DoubleTime = 0;
        var sw = new Stopwatch();
        sw.Start();

        Block = Build(code);

        sw.Stop();
        var ts = sw.Elapsed;
        Time += $"Build Time : {ts.TotalMilliseconds}ms\n";
        DoubleTime += ts.TotalMilliseconds;

        sw.Restart();
        Block.Run(ref Manager); //ref Manager
        sw.Stop();
        ts = sw.Elapsed;
        Time += $"Process Run Time : {ts.TotalMilliseconds}ms\n";
        DoubleTime += ts.TotalMilliseconds;
        Time += $"Total : {DoubleTime}ms";
    }

    public void Run(string code)
    {
        Block = Build(code);
        Block.Run(ref Manager);
    }

    private BlockOrder Build(string code)
    {
        var result = BuildResult.Parse(code);
        if (result.Errors != null && result.Errors.Count != 0)
            result.Errors.ForEach(x => Error.Add(x.ToString() ?? ""));
        return result.Result as BlockOrder ?? new BlockOrder([]);
    }

    public void Init(VariateManager manager)
    {
        Manager = manager;
    }
}